<?php
/**
 * @author jonathan poelen <jonathan.poelen@gmail.com>
 * @version 1.0: jo_link_noir
 * @date 04-06-2009
 */
abstract class SW_Structure_DAO extends SW_DAO implements SW_Structure_DAO_Interface
{
	/**
	 * Ajoute une liste de construction et retourne son id
	 * @param int $id_structure
	 * @param int $level
	 * @param int $duration
	 * @param int $time_end
	 * @param int $id_planet
	 * @return int
	 */
	abstract protected function insertList($id_structure, $level, $duration, $time_end, $id_planet);

	/**
	 * Ajoute une $id_user et retourne son id d'enregistrement
	 * @param int $id_planet
	 * @param int $group
	 * @param int $level
	 * @return int
	 */
	abstract protected function insertElement($id_planet, $group, $level);


	/** @var string : table qui pointe vers les référence de la table structure*/
	protected $tableReferencingStructure;

	/** @var string : nom de la table structure*/
	protected $tableStructure;

	/** @var string : nom de la table list*/
	protected $tableList;

	/** @var string : référence de la table structure vers une autre table*/
	protected $refPlayer;

	/** @var string : référence de la table structure vers une autre table*/
	protected $refPlanet;

	/** @var string : référence de la table list vers la table structure*/
	protected $refStructure;


	/**
	 * @param string $tableReferencingStructure : table qui pointe vers les référence de la table structure
	 * @param string $tableStructure : nom de la table structure
	 * @param string $tableList = null : nom de la table list. Si non précisé $tableStructure.'_list'
	 * @param string $refPlayer = null : référence de la table structure vers la table player (si null alors = ref_player)
	 * @param string $refPlanet = null : référence de la table structure vers une autre table
	 * @param string $refStructure = null : référence de la table list vers la table structure
	 * @param PDO $pdo = null : si null alors = SW_DAO::getDB()
	 */
	public function __construct(
		$tableReferencingStructure,
		$tableStructure,
		$tableList = null,

		$refPlayer = null,
		$refPlanet = null,
		$refStructure = null,

		PDO $pdo = null
	)
	{
		$this->tableReferencingStructure = '`'.$tableReferencingStructure.'`';
		$this->tableStructure	= '`'.$tableStructure.'`';
		$this->tableList		= '`'.($tableList ? $tableList : $tableStructure.'_list').'`';

		$this->refPlayer = '`'.($refPlayer ? $refPlayer : 'ref_player').'`';
		$this->refPlanet = '`'.($refPlanet ? $refPlanet : 'ref_'.$tableReferencingStructure).'`';
		$this->refStructure = '`'.($refStructure ? $refStructure : 'ref_'.$tableStructure).'`';

		parent::__construct($pdo);
	}

	/**
	 * Créé l'index pour les méthdoes préparé sur une structure
	 * @return string
	 */
	protected function nameMethodStructure($method)
	{
		return $method.'.'.$this->tableStructure;
	}

	/**
	 * Créé l'index pour les méthdoes préparé sur une list
	 * @return string
	 */
	protected function nameMethodList($method)
	{
		return $method.'.'.$this->tableList;
	}

	/**
	 * @param int $id
	 * @param int $id_structure
	 * @param int $level
	 * @param int $duration
	 * @param int $time_end
	 * @param int $id_planet = null
	 * @return SW_Structure_List
	 */
	protected function newList($id, $id_structure, $level, $duration, $time_end, $id_planet = null)
	{
		return new SW_Structure_List($id, $id_structure, $level, $duration, $time_end);
	}

	/**
	 * @param int $id
	 * @param int $group
	 * @param int $level
	 * @param int $id_planet = null
	 * @param int $duration = null
	 * @param array $price = null
	 * @param int $time_end = null
	 * @return SW_Structure_Element
	 */
	protected function newElement($id, $group, $level, $id_planet = null, $duration = null, array $price = null, $time_end = null)
	{
		return new SW_Structure_Element($id, $group, $level);
	}

	/**
	 * Ajoute une structure et retourne son id d'enregistrement
	 * @param int $id_planet
	 * @param int $group
	 * @param int $level
	 * @return SW_Structure_Element
	 */
	public function createElement($id_planet, $group, $level)
	{
		return $this->newElement($this->insertElement($id_planet, $group, $level), $group, $level, $id_planet);
	}

	/**
	 * Insert une nouvelle liste de construction via un élement
	 * @param SW_Structure_Element $element
	 * @param int $timestamp
	 * @param int $id_planet
	 * @param int $count : nombre pour faire évoluer la structure
	 * @return SW_Structure_List
	 */
	public function createList(SW_Structure_Element $element, $timestamp, $id_planet, $count)
	{
		return $this->newList(
			$this->insertList(
				$element->getId(),
				$count,
				$element->getDuration(),
				$element->getDuration() + $timestamp,
				$id_planet
			),
			$element->getId(),
			$count,
			$element->getDuration(),
			$element->getDuration() + $timestamp,
			$id_planet
		);
	}

	/**
	 * @param int $id_structure
	 */
	public function delete($id_structure)
	{
		$this->pdo->query('DELETE FROM '.$this->tableStructure.' WHERE id='.((int)$id_structure));
	}

	/**
	 * @param array $ids_structure
	 */
	public function deleteElements(array $ids_structure)
	{
		$this->pdo->query('DELETE FROM '.$this->tableStructure.' WHERE id IN('.explode(',',$ids_structure).')');
	}

	/**
	 * @param int $id_list
	 */
	public function deleteList($id_list)
	{
		$method = $this->nameMethodList(__METHOD__);
		if (!isset(self::$queries[$method]))
			$this->prepare($method, 'DELETE FROM '.$this->tableList.' WHERE id=?');

		self::$queries[$method]->execute(
			array($id_list)
		);
	}

	/**
	 * @param array $ids_structure
	 */
	public function deleteLists(array $ids_structure)
	{
		$this->pdo->query('DELETE FROM '.$this->tableList.' WHERE '.$this->refStructure.' IN('.explode(',',$ids_structure).')');
	}

	/**
	 * @param SW_Structure_Element $element
	 */
	public function update(SW_Structure_Element $element)
	{
		$method = $this->nameMethodStructure(__METHOD__);
		if (!isset(self::$queries[$method]))
			$this->prepare($method, 'UPDATE '.$this->tableStructure.' SET level=? WHERE id=?');

		self::$queries[$method]->execute(
			array($element->getLevel(), $element->getId())
		);
	}

	/**
	 * Commence la construction d'un élément
	 * @param SW_Structure $structure
	 * @param SW_Structure_Element $element
	 * @param int $timestamp
	 * @param int $count : nombre pour faire évoluer la structure
	 * @return SW_Structure_List
	 */
	public function build(SW_Structure $structure, SW_Structure_Element $element, $timestamp, $count)
	{
		$resource = $structure->getSiblingInstance(U1_Resource::INDEX);

		$this->pdo->beginTransaction();
		try
		{
			//on soustrait les ressources (peux retourner une exception du type SW_Resource_Exception)
			$resource->decrease($element->getPrice(), $timestamp);

			//On démarre une liste de construction
			$list = $this->createList($element, $timestamp, $structure->getIdPlanet(), $count);

			$this->pdo->commit();
			return $list;
		}
		catch (Exception $e)
		{
			$this->pdo->rollBack();
			throw $e;
		}
	}

	/**
	 * Finit la construction d'un élément
	 * @param SW_Structure_Element $element
	 * @param SW_Structure_List $list
	 */
	public function finish(SW_Structure_Element $element, SW_Structure_List $list)
	{
		$this->pdo->beginTransaction();
		//modifie le niveau
		$this->update($element);
		//supprime la list
		$this->deleteList($list->getId());
		$this->pdo->commit();
	}

	/**
	 * Supprime les table structure et list
	 */
	public function deleteTable()
	{
		return $this->pdo->query('DROP TABLE '.$this->tableStructure.', '.$this->tableList);
	}
}